package com.eight.cloud.excel.utils;

import cn.hutool.core.text.StrPool;
import com.eight.cloud.core.global.constant.StrConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static com.eight.cloud.core.global.constant.NumConstant.*;

/**
 * EasyExcel 枚举转换工具
 * 本工具类用于处理枚举值的转换和反向转换，适用于 EasyExcel 导入导出场景。
 *
 * @ClassName: DictExpConvertUtil
 * @Author: TXC
 * @Date: 2025-08-08 09:04
 **/
@Slf4j
public class DictExpConvertUtil {
    // 默认使用的分隔符
    private static final String DEFAULT_SEPARATOR = StrPool.COMMA;

    /**
     * 解析导出值
     *
     * @param propertyValue 参数值（示例：0），需要进行转换的原始值
     * @param converterExp 解析表达式（示例：0=男,1=女,2=未知），定义了值与其对应的标签
     * @param separator 分隔符（默认：,），用于分隔多个键值对
     * @param defaultValue 默认值，当无法找到对应值时返回的值
     * @return 解析后值，如果未找到对应值则返回 defaultValue
     */
    public static String convertByExp(String propertyValue, String converterExp, String separator, String defaultValue) {
        validateInputs(propertyValue, converterExp, separator);
        Map<String, String> convertMap = buildConvertMap(converterExp, separator);
        return mateConvertStr(propertyValue, separator, convertMap, defaultValue);
    }

    /**
     * 反向解析值（默认：,）
     *
     * @param propertyValue 参数值（示例：男），需要进行反向转换的标签
     * @param converterExp 解析表达式（示例：0=男,1=女,2=未知），定义了标签与其对应的值
     * @param defaultValue 默认值，当无法找到对应标签时返回的值
     * @return 反向解析后值，如果未找到对应标签则返回 defaultValue
     */
    public static String reverseByExp(String propertyValue, String converterExp, String defaultValue) {
        return reverseByExp(propertyValue, converterExp, DEFAULT_SEPARATOR, defaultValue);
    }

    /**
     * 反向解析值
     *
     * @param propertyValue 参数值（示例：男），需要进行反向转换的标签
     * @param converterExp 解析表达式（示例：0=男,1=女,2=未知），定义了标签与其对应的值
     * @param separator 分隔符（默认：,），用于分隔多个键值对
     * @param defaultValue 默认值，当无法找到对应标签时返回的值
     * @return 反向解析后值，如果未找到对应标签则返回 defaultValue
     */
    public static String reverseByExp(String propertyValue, String converterExp, String separator, String defaultValue) {
        validateInputs(propertyValue, converterExp, separator);
        Map<String, String> reverseMap = buildReverseMap(converterExp, separator);
        return mateConvertStr(propertyValue, separator, reverseMap, defaultValue);
    }

    /**
     * 验证输入参数的有效性
     *
     * @param propertyValue 参数值，需要进行转换的原始值
     * @param converterExp 解析表达式，定义了值与其对应的标签
     * @param separator 分隔符，用于分隔多个键值对
     * @throws IllegalArgumentException 如果输入无效，则抛出异常
     */
    private static void validateInputs(String propertyValue, String converterExp, String separator) {
        if (StringUtils.isBlank(separator)) {
            throw new IllegalArgumentException("Separator cannot be empty");
        }
        if (StringUtils.isBlank(converterExp)) {
            throw new IllegalArgumentException("Converter expression cannot be empty");
        }
        if (propertyValue == null) {
            throw new IllegalArgumentException("Property value cannot be null");
        }
    }

    /**
     * 构建转换映射表
     *
     * @param converterExp 解析表达式，定义了值与其对应的标签
     * @param separator 分隔符，用于分隔多个键值对
     * @return 转换映射表，键为原始值，值为对应的标签
     */
    private static Map<String, String> buildConvertMap(String converterExp, String separator) {
        return getStringStringMap(converterExp, separator, Boolean.FALSE);
    }

    /**
     * 构建反向映射表
     *
     * @param converterExp 解析表达式，定义了标签与其对应的值
     * @param separator 分隔符，用于分隔多个键值对
     * @return 反向映射表，键为标签，值为对应的原始值
     */
    private static Map<String, String> buildReverseMap(String converterExp, String separator) {
        return getStringStringMap(converterExp, separator, Boolean.TRUE);
    }

    /**
     * 构建映射表
     * @param converterExp 解析表达式，定义了值与其对应的标签或标签与其对应的值
     * @param separator 分隔符，用于分隔多个键值对
     * @param isReverse 是否反向映射，true表示标签到值的映射，false表示值到标签的映射
     * @return 映射表，键为原始值或标签，值为对应的标签或原始值
     */
    private static Map<String, String> getStringStringMap(String converterExp, String separator, boolean isReverse) {
        Map<String, String> convertMap = new ConcurrentHashMap<>();
        String[] convertSource = converterExp.split(separator);
        for (String item : convertSource) {
            String[] itemArray = item.split(StrConstant.EQUAL);
            if (itemArray.length == TWO) {
                if (isReverse) {
                    convertMap.put(itemArray[ONE], itemArray[ZERO]);
                } else {
                    convertMap.put(itemArray[ZERO], itemArray[ONE]);
                }
            }
        }
        return convertMap;
    }

    /**
     * 将属性值转换为对应的标签或返回默认值
     *
     * @param propertyValue 参数值（示例：0或多个值用分隔符分隔）
     * @param separator 分隔符，用于分隔多个值
     * @param dataMap 映射表，定义了值与其对应的标签
     * @param defaultValue 默认值，当无法找到对应值时返回的值
     * @return 解析后值，如果未找到对应值则返回 defaultValue
     */
    private static String mateConvertStr(String propertyValue, String separator, Map<String, String> dataMap,
                                      String defaultValue) {
        StringBuilder propertyString = new StringBuilder();
        // 检查 propertyValue 是否包含分隔符
        if (StringUtils.contains(propertyValue, separator)) {
            String[] values = propertyValue.split(separator);
            for (String value : values) {
                String originalValue = dataMap.getOrDefault(value, defaultValue);
                propertyString.append(originalValue).append(separator);
            }
            // 去掉末尾的分隔符
            return StringUtils.stripEnd(propertyString.toString(), separator);
        }
        // 单值处理
        return dataMap.getOrDefault(propertyValue, defaultValue);
    }
}
